home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / ccm / Settings.py < prev    next >
Encoding:
Python Source  |  2009-03-04  |  48.4 KB  |  1,525 lines

  1. #!/usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3.  
  4. # This program is free software; you can redistribute it and/or
  5. # modify it under the terms of the GNU General Public License
  6. # as published by the Free Software Foundation; either version 2
  7. # of the License, or (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful, 
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program; if not, write to the Free Software
  16. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  17. #
  18. # Authors: Quinn Storm (quinn@beryl-project.org)
  19. #          Patrick Niklaus (marex@opencompositing.org)
  20. #          Guillaume Seguin (guillaume@segu.in)
  21. #          Christopher Williams (christopherw@verizon.net)
  22. # Copyright (C) 2007 Quinn Storm
  23.  
  24. import pygtk
  25. import gtk
  26. import gobject
  27. import os
  28.  
  29. from ccm.Constants import *
  30. from ccm.Conflicts import *
  31. from ccm.Widgets import *
  32. from ccm.Utils import *
  33. from ccm.Pages import *
  34.  
  35. import locale
  36. import gettext
  37. locale.setlocale(locale.LC_ALL, "")
  38. gettext.bindtextdomain("ccsm", DataDir + "/locale")
  39. gettext.textdomain("ccsm")
  40. _ = gettext.gettext
  41.  
  42. NAItemText = _("N/A")
  43.  
  44. class Setting(object):
  45.  
  46.     NoneValue = ''
  47.  
  48.     def __init__(self, Setting=None, Settings=None, List=False):
  49.         self.Setting = Setting
  50.         self.Settings = Settings # for multi-list settings
  51.         self.List = List
  52.         if List:
  53.             self.CurrentRow = None
  54.  
  55.         self.Blocked = 0
  56.         self.EBox = gtk.EventBox()
  57.         self.Box = gtk.HBox()
  58.         self.EBox.set_visible_window(False)
  59.         if Setting:
  60.             self.EBox.set_sensitive(not Setting.ReadOnly)
  61.         self.Box.set_spacing(5)
  62.         self.EBox.add(self.Box)
  63.         self.Reset = gtk.Button()
  64.         if not Settings:
  65.             self.MakeLabel()
  66.             markup = "%s\n<small><i>%s</i></small>" % (self.Setting.LongDesc, self.Setting.Name)
  67.             self.EBox.set_tooltip_markup(markup)
  68.             self.Reset.set_tooltip_text(_("Reset setting to the default value"))
  69.         self.Reset.set_image (Image (name = gtk.STOCK_CLEAR, type = ImageStock,
  70.                                      size = gtk.ICON_SIZE_BUTTON))
  71.         self.Reset.connect('clicked', self.DoReset)
  72.         self._Init()
  73.  
  74.         self.EBox.connect("destroy", self.OnDestroy)
  75.  
  76.         self.AddUpdater()
  77.  
  78.     def AddUpdater(self):
  79.         GlobalUpdater.Append(self)
  80.  
  81.     def RemoveUpdater(self):
  82.         GlobalUpdater.Remove(self)
  83.  
  84.     def OnDestroy(self, widget):
  85.         self.RemoveUpdater()
  86.  
  87.     def GetColumn(self, num):
  88.         return (str, gtk.TreeViewColumn(self.Setting.ShortDesc, gtk.CellRendererText(), text=num))
  89.  
  90.     def PureVirtual (self, func):
  91.         message = "Missing %(function)s function for %(name)s setting (%(class)s)"
  92.  
  93.         msg_dict = {'function': func,
  94.                     'name': self.Setting.Name,
  95.                     'class': self}
  96.  
  97.         value = message % msg_dict
  98.         raise PureVirtualError, value
  99.  
  100.     def _Init(self):
  101.         self.PureVirtual('_Init')
  102.     
  103.     def DoReset(self, foo):
  104.         self.Setting.Reset()
  105.         self.Setting.Plugin.Context.Write()
  106.         self.Read()
  107.  
  108.     def MakeLabel(self):
  109.  
  110.         if not self.Setting:
  111.             return
  112.  
  113.         label = gtk.Label()
  114.         desc = protect_pango_markup (self.Setting.ShortDesc)
  115.         style = "%s"
  116.         if self.Setting.Integrated:
  117.             style = "<i>%s</i>"
  118.         label.set_markup(style % desc)
  119.         label.props.xalign = 0
  120.         label.set_size_request(160, -1)
  121.         label.props.wrap_mode = pango.WRAP_WORD
  122.         label.set_line_wrap(True)
  123.         self.Label = label
  124.  
  125.     def Block(self):
  126.         self.Blocked += 1
  127.     
  128.     def UnBlock(self):
  129.         self.Blocked -= 1
  130.  
  131.     def Read(self):
  132.         self.Block()
  133.         self._Read()
  134.         self.UnBlock()
  135.  
  136.     def _Read(self):
  137.         self.PureVirtual('_Read')
  138.  
  139.     def Changed(self, *args, **kwargs):
  140.         if self.Blocked <= 0:
  141.             self._Changed()
  142.             self.Setting.Plugin.Context.Write()
  143.  
  144.     def _Changed(self):
  145.         self.PureVirtual('_Changed')
  146.  
  147.     def Get(self):
  148.         if self.List:
  149.             if self.CurrentRow is not None:
  150.                 return self.Setting.Value[self.CurrentRow]
  151.             else:
  152.                 return self.NoneValue
  153.         else:
  154.             return self.Setting.Value
  155.     
  156.     def GetForRenderer(self):
  157.         return self.Setting.Value
  158.  
  159.     def Set(self, value):
  160.         if self.List:
  161.             if self.CurrentRow is not None:
  162.                 vlist = self.Setting.Value
  163.                 vlist[self.CurrentRow] = value
  164.                 self.Setting.Value = vlist
  165.         else:
  166.             self.Setting.Value = value
  167.  
  168.     def Swap(self, a, b):
  169.         vlist = self.Setting.Value
  170.         vlist.insert(b, vlist.pop(a))
  171.         self.Setting.Value = vlist
  172.  
  173.     def _SetHidden(self, visible):
  174.  
  175.         self.EBox.props.no_show_all = not visible
  176.  
  177.         if visible:
  178.             self.EBox.show()
  179.         else:
  180.             self.EBox.hide()
  181.  
  182.     def _Filter(self, text, level):
  183.         visible = False
  184.         if text is not None:
  185.             if level & FilterName:
  186.                 visible = (text in self.Setting.Name.lower()
  187.                     or text in self.Setting.ShortDesc.lower())
  188.             if not visible and level & FilterLongDesc:
  189.                 visible = text in self.Setting.LongDesc.lower()
  190.             if not visible and level & FilterValue:
  191.                 visible = text in str(self.Setting.Value).lower()
  192.         else:
  193.             visible = True
  194.         return visible
  195.  
  196.     def Filter(self, text, level=FilterAll):
  197.         visible = self._Filter(text, level=level)
  198.         self._SetHidden(visible)
  199.         return visible
  200.  
  201.     def __hash__(self):
  202.         if self.Setting is not None:
  203.             return hash(self.Setting)
  204.         else:
  205.             raise TypeError
  206.  
  207. class StockSetting(Setting):
  208.  
  209.     def _Init(self):
  210.         self.Box.pack_start(self.Label, False, False)
  211.         self.Box.pack_end(self.Reset, False, False)
  212.  
  213. class StringSetting(StockSetting):
  214.     def _Init(self):
  215.         StockSetting._Init(self)
  216.         self.Entry = gtk.Entry()
  217.         self.Entry.connect('activate', self.Changed)
  218.         self.Entry.connect('focus-out-event', self.Changed)
  219.         self.Widget = self.Entry
  220.         self.Box.pack_start(self.Widget, True, True)
  221.  
  222.     def _Read(self):
  223.         self.Entry.set_text(self.Get())
  224.  
  225.     def _Changed(self):
  226.         self.Set(self.Entry.get_text())
  227.  
  228. class MatchSetting(StringSetting):
  229.     def _Init(self):
  230.         StringSetting._Init(self)
  231.         self.MatchButton = MatchButton(self.Entry)
  232.         self.Box.pack_start(self.MatchButton, False, False)
  233.  
  234. class FileStringSetting(StringSetting):
  235.  
  236.     def __init__(self, setting, List=False, isImage=False, isDirectory=False):
  237.         self.isImage = isImage
  238.         self.isDirectory = isDirectory
  239.         StringSetting.__init__(self, setting, List=List)
  240.  
  241.     def _Init(self):
  242.         StringSetting._Init(self)
  243.         self.FileButton = FileButton(self.Setting.Plugin.Context, self.Entry,
  244.             self.isDirectory, self.isImage)
  245.         self.Box.pack_start(self.FileButton, False, False)
  246.  
  247. class EnumSetting(StockSetting):
  248.  
  249.     NoneValue = 0
  250.  
  251.     def _Init(self):
  252.         StockSetting._Init(self)
  253.         self.Combo = gtk.combo_box_new_text()
  254.         if self.List:
  255.             self.Info = self.Setting.Info[1][2]
  256.         else:
  257.             self.Info = self.Setting.Info[2]
  258.         self.SortedItems = sorted(self.Info.items(), key=EnumSettingKeyFunc)
  259.         for name, value in self.SortedItems:
  260.             self.Combo.append_text(name)
  261.         self.Combo.connect('changed', self.Changed)
  262.  
  263.         self.Widget = self.Combo
  264.         self.Box.pack_start(self.Combo, True, True)
  265.  
  266.     def _CellEdited(self, cell, path, new_text):
  267.         self.CurrentRow = int(path[0])
  268.         value = self.Info[new_text]
  269.         self.Store[path][self.Num] = new_text
  270.         self.Set(value)
  271.         self.Setting.Plugin.Context.Write()
  272.  
  273.     def GetColumn(self, num):
  274.         self.Num = num
  275.         cell = gtk.CellRendererCombo()
  276.         column = gtk.TreeViewColumn(self.Setting.ShortDesc, cell, text=num)
  277.         model = gtk.ListStore(str)
  278.         for property, value in [("model", model), ("text_column", 0),
  279.                                 ("editable", False), ("has_entry", False)]:
  280.             cell.set_property (property, value)
  281.         cell.connect("edited", self._CellEdited)
  282.         for item, i in self.SortedItems:
  283.             model.append([item])
  284.  
  285.         return (str, column)
  286.  
  287.     def GetForRenderer(self):
  288.         return [self.SortedItems[pos][0] for pos in self.Setting.Value]
  289.  
  290.     def _Read(self):
  291.         self.Combo.set_active(self.Get())
  292.  
  293.     def _Changed(self):
  294.         active = self.Combo.get_active_text()
  295.         
  296.         self.Set(self.Info[active])
  297.  
  298.     def _Filter(self, text, level):
  299.         visible = Setting._Filter(self, text, level=level)
  300.         if text is not None and not visible and level & FilterValue:
  301.             visible = any(text in s.lower() for s in self.Info)
  302.         return visible
  303.  
  304. class RestrictedStringSetting(StockSetting):
  305.  
  306.     NoneValue = ''
  307.  
  308.     def _Init(self):
  309.         StockSetting._Init(self)
  310.         self.Combo = gtk.combo_box_new_text()
  311.         if self.List:
  312.             info = self.Setting.Info[1]
  313.         else:
  314.             info = self.Setting.Info
  315.  
  316.         self.ItemsByName = info[0]
  317.         self.ItemsByValue = info[1]
  318.         self.SortedItems = info[2]
  319.  
  320.         # Use the first item in the list as the default value
  321.         self.NoneValue = self.ItemsByName[self.SortedItems[0][0]]
  322.  
  323.         for (i, (name, value)) in enumerate(self.SortedItems):
  324.             self.Combo.append_text(name)
  325.         self.Combo.connect('changed', self.Changed)
  326.  
  327.         self.Widget = self.Combo
  328.         self.Box.pack_start(self.Combo, True, True)
  329.  
  330.         self.OriginalValue = None
  331.         self.NAItemShift = 0
  332.  
  333.     def _CellEdited(self, cell, path, new_text):
  334.         self.CurrentRow = int(path[0])
  335.         value = self.ItemsByName[new_text]
  336.         self.Store[path][self.Num] = new_text
  337.         self.Set(value)
  338.         self.Setting.Plugin.Context.Write()
  339.  
  340.     def GetColumn(self, num):
  341.         self.Num = num
  342.         cell = gtk.CellRendererCombo()
  343.         column = gtk.TreeViewColumn(self.Setting.ShortDesc, cell, text=num)
  344.         model = gtk.ListStore(str)
  345.         for property, value in [("model", model), ("text_column", 0),
  346.                                 ("editable", False), ("has_entry", False)]:
  347.             cell.set_property (property, value)
  348.         cell.connect("edited", self._CellEdited)
  349.         for item, i in self.SortedItems:
  350.             model.append([item])
  351.  
  352.         return (str, column)
  353.  
  354.     def GetItemText (self, val):
  355.         text = self.ItemsByValue.get(val)
  356.         if text is None:
  357.             return NAItemText
  358.         return self.SortedItems[text[1]][0]
  359.  
  360.     def GetForRenderer(self):
  361.         return [self.GetItemText(val) for val in self.Setting.Value]
  362.  
  363.     def _Read(self):
  364.         value = self.Get()
  365.  
  366.         if not self.OriginalValue:
  367.             self.OriginalValue = value
  368.  
  369.             # if current value is not provided by any restricted string extension,
  370.             # insert an N/A item at the beginning
  371.             if not self.ItemsByValue.has_key(self.OriginalValue):
  372.                 self.NAItemShift = 1
  373.                 self.Combo.insert_text(0, NAItemText)
  374.  
  375.         if self.ItemsByValue.has_key(value):
  376.             self.Combo.set_active(self.ItemsByValue[self.Get()][1] + \
  377.                                   self.NAItemShift)
  378.         else:
  379.             self.Combo.set_active(0)
  380.  
  381.     def _Changed(self):
  382.         active = self.Combo.get_active_text()
  383.         
  384.         if active == NAItemText:
  385.             activeValue = self.OriginalValue
  386.         else:
  387.             activeValue = self.ItemsByName[active]
  388.         self.Set(activeValue)
  389.  
  390.     def _Filter(self, text, level):
  391.         visible = Setting._Filter(self, text, level=level)
  392.         if text is not None and not visible and level & FilterValue:
  393.             visible = any(text in s.lower() for s in self.ItemsByName)
  394.         return visible
  395.  
  396. class BoolSetting (StockSetting):
  397.  
  398.     NoneValue = False
  399.  
  400.     def _Init (self):
  401.         StockSetting._Init(self)
  402.         self.Label.set_size_request(-1, -1)
  403.         self.CheckButton = gtk.CheckButton ()
  404.         align = gtk.Alignment(yalign=0.5)
  405.         align.add(self.CheckButton)
  406.         self.Box.pack_end(align, False, False)
  407.         self.CheckButton.connect ('toggled', self.Changed)
  408.  
  409.     def _Read (self):
  410.         self.CheckButton.set_active (self.Get())
  411.  
  412.     def _Changed (self):
  413.         self.Set(self.CheckButton.get_active ())
  414.  
  415.     def CellToggled (self, cell, path):
  416.         self.CurrentRow = int(path)
  417.         self.Set(not cell.props.active)
  418.         self.Store[path][self.Num] = self.Get()
  419.         self.Setting.Plugin.Context.Write()
  420.  
  421.     def GetColumn (self, num):
  422.         self.Num = num
  423.         cell = gtk.CellRendererToggle()
  424.         cell.set_property("activatable", True)
  425.         cell.connect('toggled', self.CellToggled)
  426.         return (bool, gtk.TreeViewColumn(self.Setting.ShortDesc, cell, active=num))
  427.  
  428. class NumberSetting(StockSetting):
  429.  
  430.     NoneValue = 0
  431.  
  432.     def _Init(self):
  433.         StockSetting._Init(self)
  434.         if self.List:
  435.             self.Info = info = self.Setting.Info[1]
  436.         else:
  437.             self.Info = info = self.Setting.Info
  438.  
  439.         if self.Inc is None:
  440.             self.Inc = info[2]
  441.         inc = self.Inc
  442.         self.NoneValue = info[0]
  443.         self.Adj = gtk.Adjustment(self.Get(), info[0], info[1], inc, inc*10)
  444.         self.Spin = gtk.SpinButton(self.Adj)
  445.  
  446.         self.Scale = gtk.HScale(self.Adj)
  447.  
  448.         self.Scale.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
  449.         self.Scale.connect("value-changed", self.Changed)
  450.         self.Spin.connect("value-changed", self.Changed)
  451.         self.Widget = self.Scale
  452.  
  453.         self.Box.pack_start(self.Scale, True, True)
  454.         self.Box.pack_start(self.Spin, False, False)
  455.  
  456.     def _Read(self):
  457.         self.Adj.set_value(self.Get())
  458.  
  459.     def _Changed(self):
  460.         self.Set(self.Adj.get_value())
  461.  
  462. class IntSetting(NumberSetting):
  463.  
  464.     def _Init(self):
  465.         self.Inc = 1
  466.         NumberSetting._Init(self)
  467.         self.Spin.set_digits(0)
  468.         self.Scale.set_digits(0)
  469.  
  470. class FloatSetting(NumberSetting):
  471.  
  472.     NoneValue = 0.0
  473.  
  474.     def _Init(self):
  475.         self.Inc = None
  476.         NumberSetting._Init(self)
  477.         self.Spin.set_digits(4)
  478.         self.Scale.set_digits(4)
  479.  
  480.  
  481. class ColorSetting(StockSetting):
  482.  
  483.     NoneValue = (0, 0, 0, 65535) # opaque black
  484.  
  485.     def _Init(self):
  486.         StockSetting._Init(self)
  487.         self.Button = gtk.ColorButton()
  488.         self.Button.set_size_request (100, -1)
  489.         self.Button.set_use_alpha(True)
  490.         self.Button.connect('color-set', self.Changed)
  491.  
  492.         self.Widget = gtk.Alignment (1, 0.5)
  493.         self.Widget.add (self.Button)
  494.         self.Box.pack_start(self.Widget, True, True)
  495.  
  496.     def GetForRenderer(self):
  497.         return ["#%.4x%.4x%.4x%.4x" %tuple(seq) for seq in self.Setting.Value]
  498.  
  499.     def GetColumn(self, num):
  500.         return (str, gtk.TreeViewColumn(self.Setting.ShortDesc, CellRendererColor(), text=num))
  501.  
  502.     def _Read(self):
  503.         col = gtk.gdk.Color()
  504.         value = self.Get()
  505.         col.red, col.green, col.blue = value[:3]
  506.         self.Button.set_color(col)
  507.         self.Button.set_alpha(value[3])
  508.  
  509.     def _Changed(self):
  510.         col = self.Button.get_color()
  511.         alpha = self.Button.get_alpha()
  512.         self.Set([col.red, col.green, col.blue, alpha])
  513.  
  514. class BaseListSetting(Setting):
  515.     def _Init(self):
  516.         self.Widget = gtk.VBox()
  517.         self.EditDialog = None        
  518.         self.EditDialogOpen = False
  519.         self.PageToBeRefreshed = None
  520.  
  521.         self.Widgets = []
  522.         for i, setting in enumerate(self.Settings):
  523.             self.Widgets.append(MakeSetting(setting, List=True))
  524.  
  525.         types, cols = self.ListInfo()
  526.         self.Types = types
  527.         self.Store = gtk.ListStore(*types)
  528.         self.View = gtk.TreeView(self.Store)
  529.         self.View.set_headers_visible(True)
  530.  
  531.         for widget in self.Widgets:
  532.             widget.Store = self.Store
  533.             widget.Box.remove(widget.Reset)
  534.             widget.ListWidget = self
  535.         for col in cols:
  536.             self.View.append_column(col)
  537.  
  538.         self.View.connect('row-activated', self.Activated)
  539.         self.View.connect('button-press-event', self.ButtonPressEvent)
  540.         self.View.connect('key-press-event', self.KeyPressEvent)
  541.         self.Select = self.View.get_selection()
  542.         self.Select.set_mode(gtk.SELECTION_SINGLE)
  543.         self.Select.connect('changed', self.SelectionChanged)
  544.         self.Widget.set_spacing(5)
  545.         self.Scroll = gtk.ScrolledWindow()
  546.         self.Scroll.props.hscrollbar_policy = gtk.POLICY_AUTOMATIC
  547.         self.Scroll.props.vscrollbar_policy = gtk.POLICY_NEVER
  548.         self.Scroll.add(self.View)
  549.         self.Widget.pack_start(self.Scroll, True, True)
  550.         self.Widget.set_child_packing(self.Scroll, True, True, 0, gtk.PACK_START)
  551.         buttonBox = gtk.HBox(False)
  552.         buttonBox.set_spacing(5)
  553.         buttonBox.set_border_width(5)
  554.         self.Widget.pack_start(buttonBox, False, False)
  555.         buttonTypes = ((gtk.STOCK_NEW, self.Add, None, True),
  556.                  (gtk.STOCK_DELETE, self.Delete, None, False), 
  557.                  (gtk.STOCK_EDIT, self.Edit, None, False),
  558.                  (gtk.STOCK_GO_UP, self.Move, 'up', False), 
  559.                  (gtk.STOCK_GO_DOWN, self.Move, 'down', False),)
  560.         self.Buttons = {}
  561.         for stock, callback, data, sensitive in buttonTypes:
  562.             b = gtk.Button(stock)
  563.             b.set_use_stock(True)
  564.             buttonBox.pack_start(b, False, False)
  565.             if data is not None:
  566.                 b.connect('clicked', callback, data)
  567.             else:
  568.                 b.connect('clicked', callback)
  569.             b.set_sensitive(sensitive)
  570.             self.Buttons[stock] = b
  571.  
  572.         self.Popup = gtk.Menu()
  573.         self.PopupItems = {}
  574.         edit = gtk.ImageMenuItem(stock_id=gtk.STOCK_EDIT)
  575.         edit.connect('activate', self.Edit)
  576.         edit.set_sensitive(False)
  577.         self.Popup.append(edit)
  578.         self.PopupItems[gtk.STOCK_EDIT] = edit
  579.         delete = gtk.ImageMenuItem(stock_id=gtk.STOCK_DELETE)
  580.         delete.connect('activate', self.Delete)
  581.         delete.set_sensitive(False)
  582.         self.Popup.append(delete)
  583.         self.PopupItems[gtk.STOCK_DELETE] = delete
  584.         self.Popup.show_all()
  585.  
  586.         buttonBox.pack_end(self.Reset, False, False)
  587.  
  588.         self.Box.pack_start(self.Widget)
  589.  
  590.     def AddUpdater(self):
  591.         pass
  592.  
  593.     def RemoveUpdater(self):
  594.         if self.Settings:
  595.             for widget in self.Widgets:
  596.                 widget.EBox.destroy()
  597.  
  598.     def DoReset(self, widget):
  599.         for setting in self.Settings:
  600.             setting.Reset()
  601.         self.Settings[0].Plugin.Context.Write()
  602.         self.Read()
  603.  
  604.     def MakeLabel(self):
  605.         pass
  606.     
  607.     def Add(self, *args):
  608.         for widget, setting in zip(self.Widgets, self.Settings):
  609.             vlist = setting.Value
  610.             vlist.append(widget.NoneValue)
  611.             setting.Value = vlist
  612.         self.Settings[0].Plugin.Context.Write()
  613.         self.Read()
  614.         self._Edit(len(self.Store)-1)
  615.  
  616.     def _Delete(self, row):
  617.  
  618.         for setting in self.Settings:
  619.             vlist = setting.Value
  620.             del vlist[row]
  621.             setting.Value = vlist
  622.         self.Settings[0].Plugin.Context.Write()        
  623.  
  624.     def Delete(self, *args):
  625.         model, iter = self.Select.get_selected()
  626.         if iter is not None:
  627.             path = model.get_path(iter)
  628.             if path is not None:
  629.                 row = path[0]
  630.             else:
  631.                 return
  632.  
  633.             model.remove(iter)
  634.  
  635.             self._Delete(row)
  636.  
  637.     def _MakeEditDialog(self):
  638.         dlg = gtk.Dialog(_("Edit"))
  639.         vbox = gtk.VBox(spacing=TableX)
  640.         vbox.props.border_width = 6
  641.         dlg.vbox.pack_start(vbox, True, True)
  642.         dlg.set_default_size(500, -1)
  643.         dlg.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)
  644.         dlg.set_default_response(gtk.RESPONSE_CLOSE)
  645.  
  646.         group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
  647.         for widget in self.Widgets:
  648.             vbox.pack_start(widget.EBox, False, False)
  649.             group.add_widget(widget.Label)
  650.         return dlg
  651.  
  652.     def Edit(self, widget):
  653.         model, iter = self.Select.get_selected()
  654.         if iter:
  655.             path = model.get_path(iter)
  656.             if path is not None:
  657.                 row = path[0]
  658.             else:
  659.                 return
  660.  
  661.             self._Edit(row)
  662.  
  663.     def _Edit(self, row):
  664.         if not self.EditDialog:
  665.             self.EditDialog = self._MakeEditDialog()
  666.  
  667.         for widget in self.Widgets:
  668.             widget.CurrentRow = row
  669.             widget.Read()
  670.  
  671.         self.EditDialogOpen = True
  672.         self.EditDialog.show_all()
  673.         response = self.EditDialog.run()
  674.         self.EditDialog.hide_all()
  675.         self.EditDialogOpen = False
  676.  
  677.         if self.PageToBeRefreshed:
  678.             self.PageToBeRefreshed[0].RefreshPage(self.PageToBeRefreshed[1],
  679.                                                   self.PageToBeRefreshed[2])
  680.             self.PageToBeRefreshed = None
  681.  
  682.         self.Read()
  683.  
  684.     def Move(self, widget, direction):
  685.         model, iter = self.Select.get_selected()
  686.         if iter is not None:
  687.             path = model.get_path(iter)
  688.             if path is not None:
  689.                 row = path[0]
  690.             else:
  691.                 return
  692.             if direction == 'up':
  693.                 dest = row - 1
  694.             elif direction == 'down':
  695.                 dest = row + 1
  696.             for widget in self.Widgets:
  697.                 widget.Swap(row, dest)
  698.  
  699.             self.Settings[0].Plugin.Context.Write()
  700.  
  701.             order = range(len(model))
  702.             order.insert(dest, order.pop(row))
  703.             model.reorder(order)
  704.  
  705.             self.SelectionChanged(self.Select)
  706.  
  707.     def SelectionChanged(self, selection):
  708.  
  709.         model, iter = selection.get_selected()
  710.         for widget in (self.Buttons[gtk.STOCK_EDIT], self.Buttons[gtk.STOCK_DELETE],
  711.                        self.PopupItems[gtk.STOCK_EDIT], self.PopupItems[gtk.STOCK_DELETE]):
  712.             widget.set_sensitive(iter is not None)
  713.             
  714.         if iter is not None:
  715.             path = model.get_path(iter)
  716.             if path is not None:
  717.                 row = path[0]
  718.                 self.Buttons[gtk.STOCK_GO_UP].set_sensitive(row > 0)
  719.                 self.Buttons[gtk.STOCK_GO_DOWN].set_sensitive(row < (len(model) - 1))
  720.         else:
  721.             self.Buttons[gtk.STOCK_GO_UP].set_sensitive(False)
  722.             self.Buttons[gtk.STOCK_GO_DOWN].set_sensitive(False)
  723.  
  724.     def ButtonPressEvent(self, treeview, event):
  725.         if event.button == 3:
  726.             pthinfo = treeview.get_path_at_pos(int(event.x), int(event.y))
  727.             if pthinfo is not None:
  728.                 path, col, cellx, celly = pthinfo
  729.                 treeview.grab_focus()
  730.                 treeview.set_cursor(path, col, 0)
  731.                 self.Popup.popup(None, None, None, event.button, event.time)
  732.             return True
  733.  
  734.     def KeyPressEvent(self, treeview, event):
  735.         if gtk.gdk.keyval_name(event.keyval) == "Delete":
  736.             model, iter = treeview.get_selection().get_selected()
  737.             if iter is not None:
  738.                 path = model.get_path(iter)
  739.                 if path is not None:
  740.                     row = path[0]
  741.                     model.remove(iter)
  742.                     self._Delete(row)
  743.                     return True
  744.  
  745.     def ListInfo(self):
  746.         types = []
  747.         cols = []
  748.         for i, (setting, widget) in enumerate(zip(self.Settings, self.Widgets)):   
  749.             type, col = widget.GetColumn(i)
  750.             types.append(type)
  751.             cols.append(col)
  752.         return types, cols
  753.  
  754.     def Activated(self, object, path, col):
  755.         self._Edit(path[0])
  756.  
  757.     def _Read(self):        
  758.         self.Store.clear()
  759.         for values in zip(*[w.GetForRenderer() for w in self.Widgets]):
  760.             self.Store.append(values)
  761.  
  762.     def OnDestroy(self, widget):
  763.         for w in self.Widgets:
  764.             w.EBox.destroy()
  765.  
  766. class ListSetting(BaseListSetting):
  767.  
  768.     def _Init(self):
  769.         self.Settings = [self.Setting]
  770.         BaseListSetting._Init(self)
  771.  
  772. class MultiListSetting(BaseListSetting):
  773.  
  774.     def _Init(self):
  775.         self.EBox.set_tooltip_text(_("Multi-list settings. You can double-click a row to edit the values."))
  776.         BaseListSetting._Init(self)
  777.  
  778.     def Filter(self, text, level=FilterAll):
  779.         visible = False
  780.         for setting in self.Widgets:
  781.             if setting._Filter(text, level=level):
  782.                 visible = True
  783.         self._SetHidden(visible)
  784.         return visible
  785.  
  786. class EnumFlagsSetting(Setting):
  787.  
  788.     def _Init(self):
  789.         frame = gtk.Frame(self.Setting.ShortDesc)
  790.         table = gtk.Table()
  791.         
  792.         row = col = 0
  793.         self.Checks = []
  794.         sortedItems = sorted(self.Setting.Info[1][2].items(), key=EnumSettingKeyFunc)
  795.         self.minVal = sortedItems[0][1]
  796.         for key, value in sortedItems:
  797.             box = gtk.CheckButton(key)
  798.             self.Checks.append((key, box))
  799.             table.attach(box, col, col+1, row, row+1, TableDef, TableDef, TableX, TableX)
  800.             box.connect('toggled', self.Changed)
  801.             col = col+1
  802.             if col >= 3:
  803.                 col = 0
  804.                 row += 1
  805.  
  806.         vbox = gtk.VBox()
  807.         vbox.pack_start(self.Reset, False, False)
  808.  
  809.         hbox = gtk.HBox()
  810.         hbox.pack_start(table, True, True)
  811.         hbox.pack_start(vbox, False, False)
  812.  
  813.         frame.add(hbox)
  814.         self.Box.pack_start(frame, True, True)
  815.  
  816.     def _Read(self):
  817.         for key, box in self.Checks:
  818.             box.set_active(False)
  819.         for setVal in self.Setting.Value:
  820.             self.Checks[setVal-self.minVal][1].set_active(True)
  821.  
  822.     def _Changed(self):
  823.         values = []
  824.         for key, box in self.Checks:
  825.             if box.get_active():
  826.                 values.append(self.Setting.Info[1][2][key])
  827.         self.Setting.Value = values
  828.  
  829.     def _Filter(self, text, level=FilterAll):
  830.         visible = Setting._Filter(self, text, level=level)
  831.         if text is not None and not visible and level & FilterValue:
  832.             visible = any(text in s.lower() for s in self.Setting.Info[1][2])
  833.         return visible
  834.  
  835. class RestrictedStringFlagsSetting(Setting):
  836.  
  837.     def _Init(self):
  838.         frame = gtk.Frame(self.Setting.ShortDesc)
  839.         table = gtk.Table()
  840.         
  841.         row = col = 0
  842.         self.Checks = []
  843.         info = self.Setting.Info[1]
  844.         self.ItemsByName = info[0]
  845.         self.ItemsByValue = info[1]
  846.         sortedItems = info[2]
  847.         for key, value in sortedItems:
  848.             box = gtk.CheckButton(key)
  849.             self.Checks.append((key, box))
  850.             table.attach(box, col, col+1, row, row+1, TableDef, TableDef, TableX, TableX)
  851.             box.connect('toggled', self.Changed)
  852.             col = col+1
  853.             if col >= 3:
  854.                 col = 0
  855.                 row += 1
  856.  
  857.         vbox = gtk.VBox()
  858.         vbox.pack_start(self.Reset, False, False)
  859.  
  860.         hbox = gtk.HBox()
  861.         hbox.pack_start(table, True, True)
  862.         hbox.pack_start(vbox, False, False)
  863.  
  864.         frame.add(hbox)
  865.         self.Box.pack_start(frame, True, True)
  866.  
  867.     def _Read(self):
  868.         for key, box in self.Checks:
  869.             box.set_active(False)
  870.         for setVal in self.Setting.Value:
  871.             if self.ItemsByValue.has_key(setVal):
  872.                 self.Checks[self.ItemsByValue[setVal][1]][1].set_active(True)
  873.  
  874.     def _Changed(self):
  875.         values = []
  876.         for key, box in self.Checks:
  877.             if box.get_active():
  878.                 values.append(self.ItemsByName[key])
  879.         self.Setting.Value = values
  880.  
  881.     def _Filter(self, text, level=FilterAll):
  882.         visible = Setting._Filter(self, text, level=level)
  883.         if text is not None and not visible and level & FilterValue:
  884.             visible = any(text in s.lower() for s in self.ItemsByName)
  885.         return visible
  886.  
  887. class EditableActionSetting (StockSetting):
  888.  
  889.     def _Init (self, widget, action):
  890.         StockSetting._Init(self)
  891.         alignment = gtk.Alignment (0, 0.5)
  892.         alignment.add (widget)
  893.  
  894.         self.Label.set_size_request(-1, -1)
  895.  
  896.         editButton = gtk.Button ()
  897.         editButton.add (Image (name = gtk.STOCK_EDIT, type = ImageStock,
  898.                                size = gtk.ICON_SIZE_BUTTON))
  899.         editButton.set_tooltip_text(_("Edit %s" % self.Setting.ShortDesc))
  900.         editButton.connect ("clicked", self.RunEditDialog)
  901.  
  902.         action = ActionImage (action)
  903.         self.Box.pack_start (action, False, False)
  904.         self.Box.reorder_child (action, 0)
  905.         self.Box.pack_end (editButton, False, False)
  906.         self.Box.pack_end(alignment, False, False)
  907.         self.Widget = widget
  908.  
  909.  
  910.     def RunEditDialog (self, widget):
  911.         dlg = gtk.Dialog (_("Edit %s") % self.Setting.ShortDesc)
  912.         dlg.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
  913.         dlg.set_transient_for (self.Widget.get_toplevel ())
  914.         dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  915.         dlg.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK).grab_default()
  916.         dlg.set_default_response (gtk.RESPONSE_OK)
  917.         
  918.         entry = gtk.Entry (max = 200)
  919.         entry.set_text (self.GetDialogText ())
  920.         entry.connect ("activate", lambda *a: dlg.response (gtk.RESPONSE_OK))
  921.         alignment = gtk.Alignment (0.5, 0.5, 1, 1)
  922.         alignment.set_padding (10, 10, 10, 10)
  923.         alignment.add (entry)
  924.  
  925.         entry.set_tooltip_text(self.Setting.LongDesc)
  926.         dlg.vbox.pack_start (alignment)
  927.         
  928.         dlg.vbox.show_all ()
  929.         ret = dlg.run ()
  930.         dlg.destroy ()
  931.  
  932.         if ret != gtk.RESPONSE_OK:
  933.             return
  934.  
  935.         self.HandleDialogText (entry.get_text ().strip ())
  936.  
  937.     def GetDialogText (self):
  938.         self.PureVirtual ('GetDialogText')
  939.  
  940.     def HandleDialogText (self, text):
  941.         self.PureVirtual ('HandleDialogText')
  942.  
  943. class KeySetting (EditableActionSetting):
  944.  
  945.     current = ""
  946.  
  947.     def _Init (self):
  948.  
  949.         self.Button = SizedButton (minWidth = 100)
  950.         self.Button.connect ("clicked", self.RunKeySelector)
  951.         self.SetButtonLabel ()
  952.         
  953.         EditableActionSetting._Init (self, self.Button, "keyboard")
  954.  
  955.     def DoReset (self, widget):
  956.         conflict = KeyConflict (self.Setting, self.Setting.DefaultValue)
  957.         if conflict.Resolve (GlobalUpdater):
  958.             self.Setting.Reset ()
  959.             self.Setting.Plugin.Context.Write ()
  960.             self.Read ()
  961.  
  962.     def ReorderKeyString (self, accel):
  963.         key, mods = gtk.accelerator_parse (accel)
  964.         return gtk.accelerator_name (key, mods)
  965.  
  966.     def GetDialogText (self):
  967.         return self.current
  968.  
  969.     def HandleDialogText (self, accel):
  970.         name = self.ReorderKeyString (accel)
  971.         if len (accel) != len (name):
  972.             accel = protect_pango_markup (accel)
  973.             ErrorDialog (self.Widget.get_toplevel (),
  974.                          _("\"%s\" is not a valid shortcut") % accel)
  975.             return
  976.         self.BindingEdited (accel)
  977.  
  978.     def GetLabelText (self, text):
  979.         if not len (text) or text.lower() == "disabled":
  980.             text = _("Disabled")
  981.         return text
  982.  
  983.     def SetButtonLabel (self):
  984.         self.Button.set_label (self.GetLabelText (self.current))
  985.  
  986.     def RunKeySelector (self, widget):
  987.  
  988.         def ShowHideBox (button, box, dialog):
  989.             if button.get_active ():
  990.                 box.show ()
  991.             else:
  992.                 box.hide ()
  993.                 dialog.resize (1, 1)
  994.  
  995.         def HandleGrabberChanged (grabber, key, mods, label, selector):
  996.             new = gtk.accelerator_name (key, mods)
  997.             mods = ""
  998.             for mod in KeyModifier:
  999.                 if "%s_L" % mod in new:
  1000.                     new = new.replace ("%s_L" % mod, "<%s>" % mod)
  1001.                 if "%s_R" % mod in new:
  1002.                     new = new.replace ("%s_R" % mod, "<%s>" % mod)
  1003.                 if "<%s>" % mod in new:
  1004.                     mods += "%s|" % mod
  1005.             mods.rstrip ("|")
  1006.             label.set_text (self.GetLabelText (new))
  1007.             selector.current = mods
  1008.  
  1009.         def HandleModifierAdded (selector, modifier, label):
  1010.             current = label.get_text ()
  1011.             if current == _("Disabled"):
  1012.                 current = "<%s>" % modifier
  1013.             else:
  1014.                 current = ("<%s>" % modifier) + current
  1015.             label.set_text (self.ReorderKeyString (current))
  1016.  
  1017.         def HandleModifierRemoved (selector, modifier, label):
  1018.             current = label.get_text ()
  1019.             if "<%s>" % modifier in current:
  1020.                 new = current.replace ("<%s>" % modifier, "")
  1021.             elif "%s_L" % modifier in current:
  1022.                 new = current.replace ("%s_L" % modifier, "")
  1023.             elif "%s_R" % modifier in current:
  1024.                 new = current.replace ("%s_R" % modifier, "")
  1025.             label.set_text (self.GetLabelText (new))
  1026.  
  1027.         dlg = gtk.Dialog (_("Edit %s") % self.Setting.ShortDesc)
  1028.         dlg.set_position (gtk.WIN_POS_CENTER_ALWAYS)
  1029.         dlg.set_transient_for (self.Widget.get_toplevel ())
  1030.         dlg.set_icon (self.Widget.get_toplevel ().get_icon ())
  1031.         dlg.set_modal (True)
  1032.         dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  1033.         dlg.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK).grab_default ()
  1034.         dlg.set_default_response (gtk.RESPONSE_OK)
  1035.  
  1036.         mainBox = gtk.VBox ()
  1037.         alignment = gtk.Alignment ()
  1038.         alignment.set_padding (10, 10, 10, 10)
  1039.         alignment.add (mainBox)
  1040.         dlg.vbox.pack_start (alignment)
  1041.  
  1042.         checkButton = gtk.CheckButton (_("Enabled"))
  1043.         active = len (self.current) \
  1044.                  and self.current.lower () not in ("disabled", "none")
  1045.         checkButton.set_active (active)
  1046.         checkButton.set_tooltip_text(self.Setting.LongDesc)
  1047.         mainBox.pack_start (checkButton)
  1048.  
  1049.         box = gtk.VBox ()
  1050.         checkButton.connect ("toggled", ShowHideBox, box, dlg)
  1051.         mainBox.pack_start (box)
  1052.  
  1053.         currentMods = ""
  1054.         for mod in KeyModifier:
  1055.             if "<%s>" % mod in self.current:
  1056.                 currentMods += "%s|" % mod
  1057.         currentMods.rstrip ("|")
  1058.         modifierSelector = ModifierSelector (currentMods)
  1059.         modifierSelector.set_tooltip_text (self.Setting.LongDesc)
  1060.         alignment = gtk.Alignment (0.5)
  1061.         alignment.add (modifierSelector)
  1062.         box.pack_start (alignment)
  1063.  
  1064.         key, mods = gtk.accelerator_parse (self.current)
  1065.         grabber = KeyGrabber (key = key, mods = mods,
  1066.                               label = _("Grab key combination"))
  1067.         grabber.set_tooltip_text (self.Setting.LongDesc)
  1068.         box.pack_start (grabber)
  1069.  
  1070.         label = gtk.Label (self.current)
  1071.         label.set_tooltip_text (self.Setting.LongDesc)
  1072.         alignment = gtk.Alignment (0.5, 0.5)
  1073.         alignment.set_padding (15, 0, 0, 0)
  1074.         alignment.add (label)
  1075.         box.pack_start (alignment)
  1076.  
  1077.         modifierSelector.connect ("added", HandleModifierAdded, label)
  1078.         modifierSelector.connect ("removed", HandleModifierRemoved, label)
  1079.         grabber.connect ("changed", HandleGrabberChanged, label,
  1080.                          modifierSelector)
  1081.         grabber.connect ("current-changed", HandleGrabberChanged, label,
  1082.                          modifierSelector)
  1083.  
  1084.         dlg.vbox.show_all ()
  1085.         ShowHideBox (checkButton, box, dlg)
  1086.         ret = dlg.run ()
  1087.         dlg.destroy ()
  1088.  
  1089.         if ret != gtk.RESPONSE_OK:
  1090.             return
  1091.  
  1092.         if not checkButton.get_active ():
  1093.             self.BindingEdited ("Disabled")
  1094.             return
  1095.  
  1096.         new = label.get_text ()
  1097.  
  1098.         new = self.ReorderKeyString (new)
  1099.  
  1100.         self.BindingEdited (new)
  1101.  
  1102.     def BindingEdited (self, accel):
  1103.         '''Binding edited callback'''
  1104.         # Update & save binding
  1105.         conflict = KeyConflict (self.Setting, accel)
  1106.         if conflict.Resolve (GlobalUpdater):
  1107.             self.current = accel
  1108.             self.Changed ()
  1109.         self.SetButtonLabel ()
  1110.  
  1111.     def _Read (self):
  1112.         self.current = self.Get()
  1113.         self.SetButtonLabel ()
  1114.  
  1115.     def _Changed (self):
  1116.         self.Set(self.current)
  1117.  
  1118. class ButtonSetting (EditableActionSetting):
  1119.  
  1120.     current = ""
  1121.  
  1122.     def _Init (self):
  1123.  
  1124.         self.Button = SizedButton (minWidth = 100)
  1125.         self.Button.connect ("clicked", self.RunButtonSelector)
  1126.         self.Button.set_tooltip_text(self.Setting.LongDesc)
  1127.         self.SetButtonLabel ()
  1128.         
  1129.         EditableActionSetting._Init (self, self.Button, "button")
  1130.  
  1131.     def DoReset (self, widget):
  1132.         conflict = ButtonConflict (self.Setting, self.Setting.DefaultValue)
  1133.         if conflict.Resolve (GlobalUpdater):
  1134.             self.Setting.Reset ()
  1135.             self.Setting.Plugin.Context.Write ()
  1136.             self.Read ()
  1137.  
  1138.     def ReorderButtonString (self, old):
  1139.         new = ""
  1140.         edges = map (lambda e: "%sEdge" % e, Edges)
  1141.         for s in edges + KeyModifier:
  1142.             if "<%s>" % s in old:
  1143.                 new += "<%s>" % s
  1144.         for i in range (99, 0, -1):
  1145.             if "Button%d" % i in old:
  1146.                 new += "Button%d" % i
  1147.                 break
  1148.         return new
  1149.  
  1150.     def GetDialogText (self):
  1151.         return self.current
  1152.  
  1153.     def HandleDialogText (self, button):
  1154.         def ShowErrorDialog (button):
  1155.             button = protect_pango_markup (button)
  1156.             ErrorDialog (self.Widget.get_toplevel (),
  1157.                          _("\"%s\" is not a valid button") % button)
  1158.         if button.lower ().strip () in ("", "disabled", "none"):
  1159.             self.ButtonEdited ("Disabled")
  1160.             return
  1161.         new = self.ReorderButtonString (button)
  1162.         if len (button) != len (new):
  1163.             ShowErrorDialog (button)
  1164.             return
  1165.         self.ButtonEdited (new)
  1166.  
  1167.     def SetButtonLabel (self):
  1168.         label = self.current
  1169.         if not len (self.current) or self.current.lower() == "disabled":
  1170.             label = _("Disabled")
  1171.         self.Button.set_label (label)
  1172.  
  1173.     def RunButtonSelector (self, widget):
  1174.         def ShowHideBox (button, box, dialog):
  1175.             if button.get_active ():
  1176.                 box.show ()
  1177.             else:
  1178.                 box.hide ()
  1179.                 dialog.resize (1, 1)
  1180.         dlg = gtk.Dialog (_("Edit %s") % self.Setting.ShortDesc)
  1181.         dlg.set_position (gtk.WIN_POS_CENTER_ALWAYS)
  1182.         dlg.set_transient_for (self.Widget.get_toplevel ())
  1183.         dlg.set_modal (True)
  1184.         dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  1185.         dlg.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK).grab_default ()
  1186.         dlg.set_default_response (gtk.RESPONSE_OK)
  1187.  
  1188.         mainBox = gtk.VBox ()
  1189.         alignment = gtk.Alignment ()
  1190.         alignment.set_padding (10, 10, 10, 10)
  1191.         alignment.add (mainBox)
  1192.         dlg.vbox.pack_start (alignment)
  1193.  
  1194.         checkButton = gtk.CheckButton (_("Enabled"))
  1195.         active = len (self.current) \
  1196.                  and self.current.lower () not in ("disabled", "none")
  1197.         checkButton.set_active (active)
  1198.         checkButton.set_tooltip_text (self.Setting.LongDesc)
  1199.         mainBox.pack_start (checkButton)
  1200.  
  1201.         box = gtk.VBox ()
  1202.         checkButton.connect ("toggled", ShowHideBox, box, dlg)
  1203.         mainBox.pack_start (box)
  1204.  
  1205.         currentEdges = ""
  1206.         for edge in Edges:
  1207.             if "<%sEdge>" % edge in self.current:
  1208.                 currentEdges += "%s|" % edge
  1209.         currentEdges.rstrip ("|")
  1210.         edgeSelector = SingleEdgeSelector (currentEdges)
  1211.         edgeSelector.set_tooltip_text(self.Setting.LongDesc)
  1212.         box.pack_start (edgeSelector)
  1213.  
  1214.         currentMods = ""
  1215.         for mod in KeyModifier:
  1216.             if "<%s>" % mod in self.current:
  1217.                 currentMods += "%s|" % mod
  1218.         currentMods.rstrip ("|")
  1219.         modifierSelector = ModifierSelector (currentMods)
  1220.         modifierSelector.set_tooltip_text(self.Setting.LongDesc)
  1221.         box.pack_start (modifierSelector)
  1222.  
  1223.         buttonCombo = gtk.combo_box_new_text ()
  1224.         currentButton = 1
  1225.         for i in range (99, 0, -1):
  1226.             if "Button%d" % i in self.current:
  1227.                 currentButton = i
  1228.                 break
  1229.         maxButton = 9
  1230.         for i in range (1, maxButton + 1):
  1231.             button = "Button%d" % i
  1232.             buttonCombo.append_text (button)
  1233.         if currentButton > maxButton:
  1234.             buttonCombo.append_text ("Button%d" % currentButton)
  1235.             buttonCombo.set_active (maxButton)
  1236.         else:
  1237.             buttonCombo.set_active (currentButton - 1)
  1238.         buttonCombo.set_tooltip_text(self.Setting.LongDesc)
  1239.         box.pack_start (buttonCombo)
  1240.  
  1241.         dlg.vbox.show_all ()
  1242.         ShowHideBox (checkButton, box, dlg)
  1243.         ret = dlg.run ()
  1244.         dlg.destroy ()
  1245.  
  1246.         if ret != gtk.RESPONSE_OK:
  1247.             return
  1248.  
  1249.         if not checkButton.get_active ():
  1250.             self.ButtonEdited ("Disabled")
  1251.             return
  1252.  
  1253.         edges = edgeSelector.current
  1254.         modifiers = modifierSelector.current
  1255.         button = buttonCombo.get_active_text ()
  1256.  
  1257.         edges = edges.split ("|")
  1258.         if len (edges):
  1259.             edges = "<%sEdge>" % "Edge><".join (edges)
  1260.         else: edges = ""
  1261.  
  1262.         modifiers = modifiers.split ("|")
  1263.         if len (modifiers):
  1264.             modifiers = "<%s>" % "><".join (modifiers)
  1265.         else: modifiers = ""
  1266.  
  1267.         button = "%s%s%s" % (edges, modifiers, button)
  1268.         button = self.ReorderButtonString (button)
  1269.  
  1270.         self.ButtonEdited (button)
  1271.  
  1272.     def ButtonEdited (self, button):
  1273.         '''Button edited callback'''
  1274.         if button == "Button1":
  1275.             warning = WarningDialog (self.Widget.get_toplevel (),
  1276.                                      _("Using Button1 without modifiers can \
  1277. prevent any left click and thus break your configuration. Do you really want \
  1278. to set \"%s\" button to Button1 ?") % self.Setting.ShortDesc)
  1279.             response = warning.run ()
  1280.             if response != gtk.RESPONSE_YES:
  1281.                 return
  1282.         conflict = ButtonConflict (self.Setting, button)
  1283.         if conflict.Resolve (GlobalUpdater):
  1284.             self.current = button
  1285.             self.Changed ()
  1286.         self.SetButtonLabel ()
  1287.  
  1288.     def _Read (self):
  1289.         self.current = self.Get()
  1290.         self.SetButtonLabel ()
  1291.  
  1292.     def _Changed (self):
  1293.         self.Set(self.current)
  1294.  
  1295. class EdgeSetting (EditableActionSetting):
  1296.  
  1297.     current = ""
  1298.  
  1299.     def _Init (self):
  1300.  
  1301.         self.Button = SizedButton (minWidth = 100)
  1302.         self.Button.connect ("clicked", self.RunEdgeSelector)
  1303.         self.Button.set_tooltip_text(self.Setting.LongDesc)
  1304.         self.SetButtonLabel ()
  1305.  
  1306.         EditableActionSetting._Init (self, self.Button, "edges")
  1307.  
  1308.     def DoReset (self, widget):
  1309.         conflict = EdgeConflict (self.Setting, self.Setting.DefaultValue)
  1310.         if conflict.Resolve (GlobalUpdater):
  1311.             self.Setting.Reset ()
  1312.             self.Setting.Plugin.Context.Write ()
  1313.             self.Read ()
  1314.  
  1315.     def GetDialogText (self):
  1316.         return self.current
  1317.  
  1318.     def HandleDialogText (self, mask):
  1319.         edges = mask.split ("|")
  1320.         valid = True
  1321.         for edge in edges:
  1322.             if edge not in Edges:
  1323.                 valid = False
  1324.                 break
  1325.         if not valid:
  1326.             mask = protect_pango_markup (mask)
  1327.             ErrorDialog (self.Widget.get_toplevel (),
  1328.                          _("\"%s\" is not a valid edge mask") % mask)
  1329.             return
  1330.         self.EdgeEdited ("|".join (edges))
  1331.  
  1332.     def SetButtonLabel (self):
  1333.         label = self.current
  1334.         if len (self.current):
  1335.             edges = self.current.split ("|")
  1336.             edges = map (lambda s: _(s), edges)
  1337.             label = ", ".join (edges)
  1338.         else:
  1339.             label = _("None")
  1340.         self.Button.set_label (label)
  1341.  
  1342.     def RunEdgeSelector (self, widget):
  1343.         dlg = gtk.Dialog (_("Edit %s") % self.Setting.ShortDesc)
  1344.         dlg.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
  1345.         dlg.set_transient_for (self.Widget.get_toplevel ())
  1346.         dlg.set_modal (True)
  1347.         dlg.add_button (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  1348.         dlg.add_button (gtk.STOCK_OK, gtk.RESPONSE_OK).grab_default()
  1349.         dlg.set_default_response (gtk.RESPONSE_OK)
  1350.         
  1351.         selector = SingleEdgeSelector (self.current)
  1352.         alignment = gtk.Alignment ()
  1353.         alignment.set_padding (10, 10, 10, 10)
  1354.         alignment.add (selector)
  1355.  
  1356.         selector.set_tooltip_text (self.Setting.LongDesc)
  1357.         dlg.vbox.pack_start (alignment)
  1358.         
  1359.         dlg.vbox.show_all ()
  1360.         ret = dlg.run ()
  1361.         dlg.destroy ()
  1362.  
  1363.         if ret != gtk.RESPONSE_OK:
  1364.             return
  1365.  
  1366.         self.EdgeEdited (selector.current)
  1367.  
  1368.     def EdgeEdited (self, edge):
  1369.         '''Edge edited callback'''
  1370.         conflict = EdgeConflict (self.Setting, edge)
  1371.         if conflict.Resolve (GlobalUpdater):
  1372.             self.current = edge
  1373.             self.Changed ()
  1374.         self.SetButtonLabel ()
  1375.  
  1376.     def _Read (self):
  1377.         self.current = self.Get()
  1378.         self.SetButtonLabel ()
  1379.  
  1380.     def _Changed (self):
  1381.         self.Set(self.current)
  1382.         self.SetButtonLabel ()
  1383.  
  1384. class BellSetting (BoolSetting):
  1385.  
  1386.     def _Init (self):
  1387.         BoolSetting._Init (self)
  1388.         bell = ActionImage ("bell")
  1389.         self.Box.pack_start (bell, False, False)
  1390.         self.Box.reorder_child (bell, 0)
  1391.  
  1392. def MakeStringSetting (setting, List=False):
  1393.  
  1394.     if setting.Hints:
  1395.         if "file" in setting.Hints:
  1396.             if "image" in setting.Hints:
  1397.                 return FileStringSetting (setting, isImage=True, List=List)
  1398.             else:
  1399.                 return FileStringSetting (setting, List=List)
  1400.         elif "directory" in setting.Hints:
  1401.             return FileStringSetting (setting, isDirectory=True, List=List)
  1402.         else:
  1403.             return StringSetting (setting, List=List)
  1404.     elif (List and setting.Info[1][2]) or \
  1405.         (not List and setting.Info[2]):
  1406.         return RestrictedStringSetting (setting, List=List)
  1407.     else:
  1408.         return StringSetting (setting, List=List)
  1409.  
  1410. def MakeIntSetting (setting, List=False):
  1411.  
  1412.     if List:
  1413.         info = setting.Info[1][2]
  1414.     else:
  1415.         info = setting.Info[2]
  1416.  
  1417.     if info:
  1418.         return EnumSetting (setting, List=List)
  1419.     else:
  1420.         return IntSetting (setting, List=List)
  1421.  
  1422. def MakeListSetting (setting, List=False):
  1423.  
  1424.     if List:
  1425.         raise TypeError ("Lists of lists are not supported")
  1426.  
  1427.     if setting.Info[0] == "Int" and setting.Info[1][2]:
  1428.         return EnumFlagsSetting (setting)
  1429.     elif setting.Info[0] == "String" and setting.Info[1][2]:
  1430.         return RestrictedStringFlagsSetting (setting)
  1431.     else:
  1432.         return ListSetting (setting)
  1433.       
  1434. SettingTypeDict = {
  1435.     "Match": MatchSetting,
  1436.     "String": MakeStringSetting,
  1437.     "Bool": BoolSetting,
  1438.     "Float": FloatSetting,
  1439.     "Int": MakeIntSetting,
  1440.     "Color": ColorSetting,
  1441.     "List": MakeListSetting,
  1442.     "Key": KeySetting,
  1443.     "Button": ButtonSetting,
  1444.     "Edge": EdgeSetting,
  1445.     "Bell": BellSetting,
  1446. }
  1447.  
  1448. def MakeSetting(setting, List=False):
  1449.  
  1450.     if List:
  1451.         type = setting.Info[0]
  1452.     else:
  1453.         type = setting.Type
  1454.  
  1455.     stype = SettingTypeDict.get(type, None)
  1456.     if not stype:
  1457.         return
  1458.  
  1459.     return stype(setting, List=List)
  1460.  
  1461. class SubGroupArea(object):
  1462.     def __init__(self, name, subGroup):
  1463.         self.MySettings = []
  1464.         self.SubGroup = subGroup
  1465.         self.Name = name
  1466.         settings = sorted(GetSettings(subGroup), key=SettingKeyFunc)
  1467.         if not name:
  1468.             self.Child = self.Widget = gtk.VBox()
  1469.         else:
  1470.             self.Widget = gtk.Frame()
  1471.             self.Expander = gtk.Expander(name)
  1472.             self.Widget.add(self.Expander)
  1473.             self.Expander.set_expanded(False)
  1474.             self.Child = gtk.VBox()
  1475.             self.Expander.add(self.Child)
  1476.  
  1477.         self.Child.set_spacing(TableX)
  1478.         self.Child.set_border_width(TableX)
  1479.  
  1480.         # create a special widget for list subGroups
  1481.         if len(settings) > 1 and HasOnlyType(settings, 'List'):
  1482.             multiList = MultiListSetting(Settings=settings)
  1483.             multiList.Read()
  1484.             self.Child.pack_start(multiList.EBox, True, True)
  1485.             self.MySettings.append(multiList)
  1486.             self.Empty = False
  1487.             if name:
  1488.                 self.Expander.set_expanded(True)
  1489.  
  1490.             return # exit earlier to avoid unneeded logic's
  1491.         
  1492.         self.Empty = True
  1493.         for setting in settings:
  1494.             if not (setting.Plugin.Name == 'core' and setting.Name == 'active_plugins'):
  1495.                 setting = MakeSetting(setting)
  1496.                 if setting is not None:
  1497.                     setting.Read()
  1498.                     self.Child.pack_start(setting.EBox, True, True)
  1499.                     self.MySettings.append(setting)
  1500.                     self.Empty = False
  1501.  
  1502.         if name and len(settings) < 4: # ahi hay magic numbers!
  1503.             self.Expander.set_expanded(True)
  1504.  
  1505.     def Filter(self, text, level=FilterAll):
  1506.         empty = True
  1507.         count = 0
  1508.         for setting in self.MySettings:
  1509.             if setting.Filter(text, level=level):
  1510.                 empty = False
  1511.                 count += 1
  1512.  
  1513.         if self.Name:
  1514.             self.Expander.set_expanded(count < 4)
  1515.  
  1516.         self.Widget.props.no_show_all = empty
  1517.  
  1518.         if empty:
  1519.             self.Widget.hide()
  1520.         else:
  1521.             self.Widget.show()
  1522.  
  1523.         return not empty
  1524.  
  1525.